import 'dart:async';
import 'package:flutter/material.dart';

/* 
  resizeToAvoidBottomInset: false 禁止布局随着键盘上移动(上个界面可以使用，这样就不会出现键盘导致布局报错)

  点击搜索框之外的地方失去焦点从而关闭键盘，可以使用了处理键盘的一个插件：flutter_keyboard_visibility: ^5.1.0
*/

class CNMSearchBar extends StatefulWidget implements PreferredSizeWidget {
  /// 输入框高度 默认44
  final double height;

  /// 导航条高度
  final double barHeight;

  /// 导航栏背景颜色
  final Color barBgColor;

  /// 左侧小部件
  final Widget? leading;

  /// 左侧小部件宽度
  final double leadingWidth;

  /// 输入框容器圆角数
  final double borderRadius;

  /// 导航栏右侧小部件
  final List<Widget> trailings;

  /// 输入框占位文本
  final String placeholdText;

  /// 输入框占位文本样式
  final TextStyle placeholdTextStyle;

  /// 输入框文本样式
  final TextStyle inputTextTextStyle;

  /// 默认显示的搜索文本
  final String? defaultText;

  /// 输入框业务管理类
  final TextEditingController? textEditingController;

  /// 输入框焦点类
  final FocusNode? focusNode;

  /// 是否自动获取焦点
  final bool autofocus;

  /// 清除输入框内容并取消输入
  final VoidCallback? onCancel;

  /// 输入框内容改变
  final ValueChanged<String>? onChanged;

  /// 点击键盘搜索
  final ValueChanged<String>? onSearch;

  /// 点击搜索框
  final VoidCallback? onTextFieldTap;

  const CNMSearchBar({
    Key? key,
    this.height = 44,
    this.barHeight = kToolbarHeight,
    this.barBgColor = Colors.white,
    this.leading,
    this.leadingWidth = 40,
    this.borderRadius = 22,
    this.trailings = const <Widget>[],
    this.placeholdText = '请输入关键字',
    this.placeholdTextStyle = const TextStyle(
      color: Color(0xff666666),
      fontSize: 14,
    ),
    this.inputTextTextStyle = const TextStyle(
      color: Color(0xff333333),
      fontSize: 14,
    ),
    this.defaultText,
    this.textEditingController,
    this.focusNode,
    this.autofocus = false,
    this.onCancel,
    this.onChanged,
    this.onSearch,
    this.onTextFieldTap,
  }) : super(key: key);

  @override
  State<CNMSearchBar> createState() => _CNMSearchBarState();

  @override
  Size get preferredSize => Size.fromHeight(barHeight);
}

class _CNMSearchBarState extends State<CNMSearchBar> {
  late final ValueNotifier<bool> _textEmptyNotifier;

  TextEditingController? _controller;
  FocusNode? _focusNode;
  Timer? _timer;

  @override
  void initState() {
    _textEmptyNotifier = ValueNotifier((widget.defaultText ?? '').isEmpty);

    _controller = widget.textEditingController ?? TextEditingController(text: widget.defaultText);
    _focusNode = widget.focusNode ?? FocusNode();

    super.initState();
  }

  @override
  void dispose() {
    _controller!.dispose();
    _focusNode!.dispose();
    _timer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AppBar(
      elevation: 0,
      backgroundColor: widget.barBgColor,
      titleSpacing: 0,
      leadingWidth: widget.leadingWidth,
      leading: widget.leading ??
          InkWell(
            splashColor: Colors.transparent,
            highlightColor: Colors.transparent,
            child: const Icon(
              Icons.arrow_back_ios_outlined,
              color: Color(0xff666666),
              size: 20,
            ),
            onTap: () {
              _unFocus();
              Navigator.of(context).pop();
            },
          ),
      actions: widget.trailings,
      title: Container(
        height: widget.height,
        margin: const EdgeInsetsDirectional.only(end: 10),
        decoration: BoxDecoration(
          color: const Color(0xfff9f9f9),
          borderRadius: BorderRadius.circular(widget.borderRadius),
        ),
        child: Row(
          children: [
            /// 搜索 icon
            SizedBox(
              width: widget.height,
              height: widget.height,
              child: const Icon(
                Icons.search,
                size: 20,
                color: Color(0xff999999),
              ),
            ),

            /// 输入框
            Expanded(
              child: TextField(
                autofocus: widget.autofocus,
                focusNode: _focusNode,
                controller: _controller,
                textInputAction: TextInputAction.search,
                style: widget.inputTextTextStyle,
                decoration: InputDecoration(
                  isDense: true,
                  border: InputBorder.none,
                  hintText: widget.placeholdText,
                  hintStyle: widget.placeholdTextStyle,
                ),
                onTap: widget.onTextFieldTap,
                onChanged: (value) {
                  _textEmptyNotifier.value = value.isEmpty;

                  // 延迟回调
                  if (_timer != null) {
                    _timer?.cancel();
                  }
                  _timer = Timer(const Duration(milliseconds: 350), () {
                    widget.onChanged?.call(value);
                    _timer = null;
                  });
                },
                onSubmitted: (value) {
                  _unFocus();
                  widget.onSearch?.call(value);
                },
              ),
            ),

            /// 清除按钮
            ValueListenableBuilder<bool>(
              valueListenable: _textEmptyNotifier,
              builder: (context, value, child) => Container(
                margin: const EdgeInsets.only(right: 8),
                child: _CnmSearchClear(
                  isTextEmpty: value,
                  onClear: () {
                    _controller!.text = '';
                    _textEmptyNotifier.value = true;
                    widget.onCancel?.call();
                  },
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  /// 失去焦点
  void _unFocus() {
    _focusNode!.unfocus();
  }
}

class _CnmSearchClear extends StatelessWidget {
  /// 输入框是否存在文本
  final bool isTextEmpty;

  /// 点击 clear 回调
  final VoidCallback? onClear;

  const _CnmSearchClear({
    Key? key,
    this.isTextEmpty = true,
    this.onClear,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return isTextEmpty
        ? const SizedBox.shrink()
        : InkWell(
            child: const Icon(
              Icons.cancel,
              color: Color(0xff999999),
              size: 22,
            ),
            onTap: () => onClear?.call(),
          );
  }
}
